var OS3Tree = {};

OS3Tree.instances = new Array ();
/*
OS3Tree.templates = {
	node_up   : '<a href="javascript:OS3Tree._node_up(\'%(tree_id)s\',\'%(div_id)s\',\'%(node_id)s\')">^^</a>',
	node_sep  : '&nbsp;',
	node_down : '<a href="javascript:OS3Tree._node_down(\'%(tree_id)s\',\'%(div_id)s\',\'%(node_id)s\')">vv</a>'
};
*/
OS3Tree.templates = {
	node_up   : '<div class="move-up" onclick="OS3Tree._node_up(\'%(tree_id)s\',\'%(div_id)s\',\'%(node_id)s\')" title="Move Up"></div>',
	node_down : '<div class="move-down" onclick="OS3Tree._node_down(\'%(tree_id)s\',\'%(div_id)s\',\'%(node_id)s\')" title="Move Down"></div>',
	arrange_box : '<div>%(div_node_up)s%(div_node_down)s<div style="clear:both;"></div></div>'
};
OS3Tree.ERR_NO_RESULTS = -1;
OS3Tree.ERR_TOP_REACHED = -2;
OS3Tree.ERR_BOTTOM_REACHED = -3;

// ============================================================0
// Tree 
// ============================================================0

OS3Tree._int_events = {};



OS3Tree._int_events [ 'hover' ] = function ( tree, div, node )
{
	if ( tree._curr_node ) tree._curr_node._div.className = ( tree._curr_node == tree._curr_node_sel ? "sel" : "norm" );

	if ( div.className == "sel" )
		div.className = "tree_hover_sel";
	else
		div.className = "tree_hover";

	if ( tree.arrange_branches )
		OS3Tree._show_arrange ( tree, div, node );

	tree._curr_node = node;
	node._div = div;
};


OS3Tree._int_events [ 'out' ] = function ( tree, div, node )
{
	// console.debug ( "OUT: %s", div.id );
	if ( div._stop_out )
	{
		div._stop_out = false;
		return;
	}

	div.className = ( node == tree._curr_node_sel ? "sel" : "norm" );
	if ( tree.arrange_branches )
		OS3Tree._hide_arrange ( tree, div, node );
};

OS3Tree._int_events [ 'btn_down' ] = function ( tree, div, node )
{
        div.className = "btn_down";
};

OS3Tree._int_events [ 'btn_up' ] = function ( tree, div, node )
{
        div.className = "btn_up";
};

OS3Tree._int_events [ 'click' ] = function ( tree, div, node )
{
        if ( ( tree._curr_node_sel ) && ( tree._curr_node_sel == tree._curr_node ) ) 
	{
		tree._curr_node_sel = null;
		tree._curr_node._div.className = 'norm';
		node.is_selected = false;
		return;
	}

	tree.current_clear ();

        tree._curr_node_sel = tree._curr_node;
	tree._curr_node_sel.is_selected = true;
        tree._curr_node._div.className = 'sel';
};

OS3Tree._int_events [ 'node_up' ] = function ( tree, div, node )
{
	console.debug ( "Node UP!" );
};

OS3Tree._int_events [ 'node_down' ] = function ( tree, div, node )
{
	console.debug ( "Node DOWN!" );
};

// {{{ _arrange 
OS3Tree._arrange = {};

OS3Tree._arrange._div = document.createElement ( "div" );
OS3Tree._arrange._div.className = "arrange";
OS3Tree._arrange._curr_div = null;
OS3Tree._arrange._div.onmouseover = function () { 
	if ( OS3Tree._arrange._curr_div ) OS3Tree._arrange._curr_div._stop_out = true; 
};
// }}}
// {{{ _show_arrange ( tree, div, node )
OS3Tree._show_arrange = function ( tree, div, node )
{
	// console.debug ( div.innerHTML );

	if ( OS3Tree._arrange._curr_div == div ) return;

	OS3Tree._hide_arrange ();

	OS3Tree._arrange._curr_div = div;

	// Stop the "out" event on the current div when the "new" div will be appended
	// over it.
	OS3Tree._arrange._curr_div._stop_out = true;

	div.appendChild ( OS3Tree._arrange._div );

	var dct = { tree_id : tree.id, div_id: div.id, node_id: node.id };
	
	var tmpl = { 
			div_node_up : String.formatDict ( OS3Tree.templates [ 'node_up' ], dct ), 
			div_node_down : String.formatDict ( OS3Tree.templates [ 'node_down' ], dct )
		   };
	OS3Tree._arrange._div.innerHTML = String.formatDict ( OS3Tree.templates [ 'arrange_box' ], tmpl );
					  
};
// }}}
// {{{ _node_up ( tree_id, div_id, node_id )
OS3Tree._node_up = function ( tree_id, div_id, node_id )
{
	var tree = OS3Tree.instances [ tree_id ];
	var div  = document.getElementById ( div_id );
	var node = tree.nodes [ node_id ];

	OS3Tree.evt ( div, 'node_up' );
	tree.node_up ( node );
};
// }}}
// {{{ _node_down  ( tree_id, div_id, node_id )
OS3Tree._node_down = function ( tree_id, div_id, node_id )
{
	var tree = OS3Tree.instances [ tree_id ];
	var div  = document.getElementById ( div_id );
	var node = tree.nodes [ node_id ];

	OS3Tree.evt ( div, 'node_down' );
	tree.node_down ( node );
};
// }}}
// {{{ _hide_arrange ( tree, div, node )
OS3Tree._hide_arrange = function ( tree, div, node )
{
	if ( ! OS3Tree._arrange._curr_div ) return;

	console.debug ( "HIDE" );

	OS3Tree._arrange._curr_div.removeChild ( OS3Tree._arrange._div );
	OS3Tree._arrange._curr_div = null;
};
// }}}


// {{{ OS3Tree.instance = function ( id )
OS3Tree.instance = function ( id )
{
	this.id = id;

	this.show_checkbox = false;		// Flag T/F. If T, each node will have a checkbox
	this.show_folder_checkbox = true;	// Flag T/F. If T, folders will have checkbox (if show_checkbox is true)
	this.show_expand   = true;	// Flag T/F. If T, each "folder" will have an expand/collapse button
	this.folders_collapsed  = true;	// Flag T/F. If T, folders starts in "collapsed" mode
	this.expand_limit = 0;		// A value reppresenting the level of folders to show

	this.arrange_branches = false;	// Flag T/F. If T, tree branches can be moved with buttons

	this.status_img = [ 'empty', 'half', 'full' ];

	this.width = 0;		// Tree width & height. You *MUST* specify the type (CSS mode )
	this.height = 0;
	this.scrollbars = true;

	this.expand_request = null;  // Callback to be defined called when the user clicks on the "+" button
				     // exapand_request ( node_instance )

	this._events = {};		// Tree custom events
	this._blocked_events = {};	// Tree blocked events

	this._preselection = null;	// Values for selected nodes

	// ==========================================================================================================================
	// Public Methods
	// ==========================================================================================================================
	this.node_up = function ( node )
	{
		var lst, pos, l;

		if ( node.parent )
			lst = node.parent.list;
		else
			lst = this.list;

		pos = lst.indexOf ( node );
		if ( pos == 0 ) return;

		var prev = lst [ pos -1 ];
		var node_div = document.getElementById ( node.tree.id + ":" + node.id ).parentNode;
		var prev_div = document.getElementById ( prev.tree.id + ":" + prev.id ).parentNode;
		var container = prev_div.parentNode;

		container.removeChild ( node_div );
		container.insertBefore ( node_div, prev_div );

		lst [ pos ] = prev;
		lst [ pos -1 ] = node;
	};

	this.node_down = function ( node )
	{
		var lst, pos, l;

		if ( node.parent )
			lst = node.parent.list;
		else
			lst = this.list;

		pos = lst.indexOf ( node );
		if ( pos == ( lst.length -1 ) ) return;

		var next = lst [ pos + 1 ];
		var node_div = document.getElementById ( node.tree.id + ":" + node.id ).parentNode;
		var next_div = document.getElementById ( next.tree.id + ":" + next.id ).parentNode;
		var container = next_div.parentNode;

		container.removeChild ( next_div );
		container.insertBefore ( next_div, node_div );

		lst [ pos ] = next;
		lst [ pos +1 ] = node;

	};

	// {{{ add_node ( parent_node, text, id, val, onclick )
	/*
		Adds a node to the tree.

		INPUTS:
			- parent_node: 	the node that will contain this node
			- text:		text to be shown
			- id:		(optional) an ID value to be used to search the node
			- val:		(optional) value to be returned if the node is selected.
					This is used only when the OS3Tree has the ``show_checkbox`` atribute
					set to true.

		RESULT: - a valid node structure

	*/
	this.add_node = function ( parent_node, text, id, val, onclick )
	{
		var node;

		if ( ! id ) 
		{
			if ( ! parent_node )
				id = this.list.length +1;
			else
				id = parent_node.id + "_" + ( parent_node.list.length +1 );
		}

		node = new OS3Tree.Node.instance ( parent_node, text, id, val, onclick, this );

		node.expand_request = this.expand_request;
		
		// Add the new node to the ordered list
		// If ``parent_node`` is null, the new node is added to the
		// root list
		if ( ! parent_node ) 
			this.list.push ( node );
		else
		{
			parent_node.list.push ( node );
			parent_node._nodes ++;
		}

		// The ``id`` of the new node is added to the associative
		// array used to identify nodes by id
		this.nodes [ id ] = node;

		this._preselection_check ( node );

		if ( parent_node )
		{
			if ( node.status == 2 ) parent_node._selected ++;
			if ( ! parent_node._preselected ) node.status = parent_node.status == 0 ? 0 : 2;
		}

		// console.debug ( 'node %s status = %d', node.val, node.status );

		return node;
	};
	// }}}
	// {{{ add_folder ( parent_node, text, id, val, onclick )
	this.add_folder 	= function ( parent_node, text, id, val, onclick )
	{
		var n = this.add_node ( parent_node, text, id, val, onclick );

		n._is_folder = true;
		return n;
	};
	// }}}
	// {{{ get_node_by_id ( id )
	this.get_node_by_id 	= function ( id )
	{
		return this.nodes [ id ];
	};
	// }}}
	// {{{ render ( html_id )
	this.render = function ( id )
	{
		var n;
		var l = this.list.length;
		var s = new String.buffer ();

		if ( ! id ) id = this.html_id;

		s.add ( '<div id="tree:' + id + '" class="os3tree" style="overflow: ' );

		if ( this.scrollbars ) 
			s.add ( "auto;" );
		else
			s.add ( "hidden;" );

		if ( this.width ) s.add ( " width: " + this.width + ";" );
		if ( this.height ) s.add ( " height: " + this.height + ";" );

		s.add ( '">' );

		this.html_id = id;

		for ( n = 0; n < l; n ++ ) s.add (  this.list [ n ].render () );

		s.add ( '</div>' );

		document.getElementById ( this.html_id ).innerHTML = s.toString ();

		if ( ( this._post_render.length ) && ( this.expand_request ) )
		{
			for ( n = 0; n < this._post_render.length; n ++ )
				this.expand_request ( this._post_render [ n ] );
		}
	};
	// }}} 

	this.current_clear = function ()
	{
        	if ( this._curr_node_sel ) 
		{
			this._curr_node_sel._div.className = 'norm';
			this._curr_node_sel.is_selected = false;
			this._curr_node_sel = null;
		}
	};

	this.current_get = function ()
	{
		return this._curr_node_sel;
	};

	// {{{ get_selection ( folders_only )
	this.get_selection	= function ( folders_only )
	{
		var arr = new Array ();
		var l = this.list.length;
		var t;

		if ( ! folders_only ) folders_only = false;

		for  ( t = 0; t < l; t ++ ) this.list [ t ].get_selection ( arr, folders_only );

		return arr;
	};
	// }}}
	// {{{ mk_list ( mode, val )
	// Mode: 
	//		1 - Text
	//		2 - Val
	this.mk_list		= function ( mode, val )
	{
		this.res_list = new Array ();

		var l = this.list.length;
		var t;

		for  ( t = 0; t < l; t ++ ) this.list [ t ].mk_list ( mode, val );

		this.res_list_index = -1;

		return this.res_list.length;
	};
	// }}}
	// {{{ show_result_prev ()
	this.show_result_prev = function ()
	{
		if ( this.res_list.length == 0 ) return OS3Tree.ERR_NO_RESULTS;
		if ( this.res_list_index == -1 ) return OS3Tree.ERR_TOP_REACHED;
		
		var n = this.res_list [ this.res_list_index  -- ];
		var e = document.getElementById ( n.tree.id + ":" + n.id );

		n.open_parent ();

		this._hl_element ( e );

		return 0;
	};
	// }}}
	// {{{ show_result_next ()
	this.show_result_next	= function ()
	{

		if ( this.res_list.length == 0 ) return OS3Tree.ERR_NO_RESULTS;
		if ( this.res_list_index == this.res_list.length -1 ) return OS3Tree.ERR_BOTTOM_REACHED;
		
		var n = this.res_list [ ++ this.res_list_index ];
		var e = document.getElementById ( n.full_id );

		n.open_parent ();

		this._hl_element ( e );

		document.location = "#" + n.id;

		return 0;
	};
	// }}}
	// {{{ clear ()
	this.clear =  function ()
	{
		var n, l = this.list.length;
	  
		for ( n = 0; n < l; n ++ ) this.list [ n ].change_status ( 0 );
	};
	// }}}

	this.block_event = function ( event_name, mode )
	{
		if ( mode === undefined ) mode = true;
		this._blocked_events [ event_name ] = mode;
	};

	this.set_event = function ( evt_name, cback )
	{
		this._events [ evt_name ] = cback;
	};

	this.del_node = function ( node )
	{
		var lst = this.list;
		var t, l;
		var p = node.parent;

		if ( p ) lst = p.list;

		l = lst.length;

		for ( t = 0; t < l; t ++ )
			if ( lst [ t ] == node )
			{
				this._del_node ( t, lst );
				break;
			}

		if ( p ) 
		{
			p._nodes --;
			p.refresh ();
		} else {
			this._nodes --;
			this.render ();
		}

		if ( node == this._curr_node_sel )
			this._curr_node_sel = null;
		
	};

	this.preselection_set = function ( sel )
	{
		this._preselection = sel;
	};

	// ==========================================================================================================================
	// Private Methods
	// ==========================================================================================================================
	// {{{ _hl_element ( e )
	this._hl_element = function ( e )
	{
		var main_div;

		if ( this.res_list_element )
		{
			this.res_list_element.style.backgroundColor = this.res_list_element.old_col;
			this.res_list_element = null;
		}

		if ( ! e ) return;

		e.old_col = e.style.backgroundColor;
		e.style.backgroundColor = "red";
		this.res_list_element = e;

		main_div = document.getElementById ( "tree:" + this.html_id );

		main_div.scrollTop = e.offsetTop - 10;
	};
	// }}}

	this._preselection_check = function ( node )
	{
		if ( ! this._preselection ) return;

		var sel = this._preselection;
		var i, s, l = sel.length;
		var val = node.val;

		for ( i = 0; i < l; i ++ )
		{
			s = sel [ i ];
			if ( s == val )
			{
				sel.splice ( i, 1 );
				node.status = 2;
				break;
			} else if ( s.startsWith ( val ) ) {
				node.status = 1;
				node._preselected = true;
				node.expand_request ( node );
				break;
			}
		}
	};

	this._del_node = function ( pos, lst )
	{
		var node = lst [ pos ];
		var t, l = lst.length - 1;

		for ( t = l; t >= 0; t -- )
			this._del_node ( t, node.list );

		lst.splice ( pos, 1 );
	};


	// ==========================================================================================================================
	// Private Attributes
	// ==========================================================================================================================
	this.nodes = new Array();	// Nodes by id
	this.list  = new Array();	// Nodes by order (only if parent_node is NULL)
	this.html_id = 0;		// HTML id for the element to be replaced by OS3Tree

	this._post_render = new Array ();
	this.res_list = new Array();
	this.res_list_index = -1;
	this.res_list_element = null;

	// Register the Tree instance
	OS3Tree.instances [ this.id ] = this;
};
// }}}
// {{{ OS3Tree.expand ( img, force_mode )
OS3Tree.expand = function ( img, force_mode )
{
	var folder = img.parentNode;
	var e = folder.lastChild;
	var node = OS3Tree.get_node_by_id ( folder.id );

	if ( node._is_folder && node._nodes == 0 )
	{
		img.className = 'wait';
		node.expand_request ( node );
		return;
	} 

	if ( e.style.display == force_mode ) return;

	// if ( force_mode ) alert ( force_mode + " - " + e.style.display );

	if ( force_mode )
	{
		if ( force_mode == 'block' )
		{
			e.style.display = 'block';
			img.className = 'minus';
		} else {
			e.style.display = 'none';
			img.className = 'plus';
		}
	} else {
		if ( e.style.display != 'none' )
		{
			e.style.display = 'none';
			img.className = 'plus';
		} else {
			e.style.display = 'block';
			img.className = 'minus';
		}
	}
};
// }}}
// {{{ OS3Tree.get_tree_by_id ( id )
OS3Tree.get_tree_by_id = function ( id )
{
	return OS3Tree.instances [ id ];
};
// }}}
// {{{ OS3Tree.node_select ( tree_id, node_id, status, img )
OS3Tree.node_select = function ( tree_id, node_id, status, img )
{
	var new_status = 0;
	var t = OS3Tree.instances [ tree_id ];
	var n = t.nodes [ node_id ];

	if ( n.status == 0 ) return n.change_status ( 2 );

	return n.change_status ( 0 );
};
// }}}
// {{{ OS3Tree.get_node_by_id ( node_id )
OS3Tree.get_node_by_id = function ( node_id )
{
	var data = node_id.split ( ":" );
	var tree = OS3Tree.instances [ data [ 1 ] ];
	return tree.nodes [ data [ 2 ] ];
};
// }}}
OS3Tree.evt = function ( div, event_name )
{
	var values = div.id.split ( ":" );
	var tree_name = values [ 0 ];	// Tree name
	var tree = OS3Tree.instances [ tree_name ];
	var node = tree.nodes [ values [ values.length -1 ] ];

        if ( tree._blocked_events [ event_name ] ) return;
        if ( OS3Tree._int_events [ event_name ] ) OS3Tree._int_events [ event_name ] ( tree, div, node );
        if ( tree._events [ event_name ] ) tree._events [ event_name ] ( tree, event_name, div, node );
};


// ============================================================0
// Tree Node
// ============================================================0

OS3Tree.Node = {};

// {{{ OS3Tree.Node.instance ( parent_node, text, id, val, onclick, _tree )
OS3Tree.Node.instance = function ( parent_node, text, id, val, onclick, _tree )
{
	this.parent = parent_node;
	this.text   = text;
	this.id	    = id;
	this.val    = val;
	this.onclick = onclick;
	this.tree   = _tree;
	this.status = 0;	// 0 == empty, 1 == half (folders only), 2 == full
	this.full_id = _tree.id + ":" + this.id;
	this.expand_request = null;

	this.is_selected = false;
	this._preselected = false; // this node has a preselection

	this.list   = new Array ();

	if ( this.parent )
		this.level  = this.parent.level + 1;
	else
		this.level = 1;

	// {{{ render ()
	this.render = function ()
	{
		var s = new String.buffer ();
		var l = this.list.length;
		var n, cl;
		var img, show_hidden = false;

		s.add ( '<a name="' + this.full_id + '"></a>' );
		
		if ( ! this._is_folder )
		{
			s.add ( '<div class="node"><div class="void"></div>' );
			s.add ( this._mk_chkbox ( this, false ) );
			s.add ( this._mk_events ( this ) );
			s.add ( '</div>' );

			return s.toString ();
		}

		s.add ( '<div class="folder" id="folder:' + this.full_id + '">' );

		if ( this.tree.show_expand ) 
		{
			if ( ( this.tree.folders_collapsed ) && ( this.level > this.tree.expand_limit ) ) show_hidden = true;

			// if ( show_hidden == false ) callback_la_prima_volta
			if ( ( show_hidden == false ) && ( this._is_folder ) ) this.tree._post_render.push ( this );

			s.add ( '<div id="handle:' + this.full_id + '" onclick="OS3Tree.expand(this)" class="' );

			if ( show_hidden ) 
				s.add ( 'plus' );
			else
			{
				if ( this._is_folder )
				{
					if ( this._nodes )
						s.add ( 'minus' );
					else
						s.add ( 'wait' );
				} else
					s.add ( 'minus' );
			}

			s.add ( '"></div>' );
		}

		s.add ( this._mk_chkbox ( this, true ) );
		s.add ( this._mk_events ( this ) );
		s.add ( '<div class="folder_box"' );
		if ( show_hidden ) s.add ( ' style="display: none"' );
		s.add ( '>' );

		for ( n = 0; n < l; n ++ ) s.add ( this.list [ n ].render () );

		if ( this.tree.show_expand ) s.add ( '</div>' );
		s.add ( '</div>' );

		return s.toString ();
	};
	// }}}
	// {{{ change_status ( new_status )
	this.change_status = function ( new_status )
	{
		if ( this.status == new_status ) return;		// Do nothing if status has not changed

		var l = this.list.length;
		var n;
		var img = document.getElementById ( this._mk_img_id ( this ) );

		this.status = new_status;
		img.className = this.tree.status_img [ this.status ];

		if ( new_status == 2 ) this._add_node ( this.parent, new_status );
		else if ( new_status == 0 ) this._del_node ( this.parent, new_status );

		for ( n = 0; n < l; n ++ ) this.list [ n ].change_status ( new_status );
	};
	// }}}
	//  {{{ get_selection ( arr, folders_only )
	this.get_selection = function ( arr, folders_only )
	{
		var l = this.list.length;
		var t;

		if ( this.status == 2 )
		{
			if ( this.val )
				arr [ this.id ] = this.val;
			else
				arr [ this.id ] = true;

			if ( folders_only ) return;
		}

		for ( t = 0; t < l; t ++ ) this.list [ t ].get_selection ( arr, folders_only );
	};
	// }}}
	// {{{ mk_list ( mode, val )
	this.mk_list = function ( mode, val )
	{
		var l = this.list.length;
		var t;

		switch ( mode )
		{
			case 1: 	// Text
				if ( this.text.toLowerCase().indexOf ( val.toLowerCase () ) != -1 ) this.tree.res_list.push ( this );
				break;

			case 2:		// Value
				if ( this.val == val ) this.res_list.push ( this );
				break;
		}

		for ( t = 0; t < l; t ++ ) this.list [ t ].mk_list ( mode, val );
	};
	// }}}
	// {{{ expand ( mode )
	this.expand = function ( mode )
	{
		var img_name = "handle:" + this.full_id;

		if ( mode == true ) mode = "block";
		else if ( mode == false ) mode = "none";

		OS3Tree.expand ( document.getElementById ( img_name ), mode );
	};
	// }}}
	// {{{ open_parent ()
	this.open_parent   = function ()
	{
		if ( ! this.parent ) return;

		this.parent.expand ( true );
		this.parent.open_parent ();
	};
	// }}}
	// {{{ expand_done ( elems )
	this.expand_done   = function ( elems )
	{
		var img = document.getElementById ( 'handle:' + this.full_id );
		var l, t, n, node, s, folder;

		if ( ! elems ) 
		{
			// TODO: uscire senza togliendo il piu'
			return;
		}

		l = elems.length;
		for ( t = 0; t < l; t ++ )
		{
			n = elems [ t ];

			node = this.tree.add_node ( this, ( n.text ? n.text : 'NO TEXT' ), n.id, n.val, n.onclick );
			node._is_folder = n.folder ? true : false;
			//node.status = this.status == 0 ? 0 : 2;
		}

		this.refresh ();

		folder = document.getElementById ( 'folder:' + this.full_id ).lastChild;
		folder.style.display = 'block';
		img.className = 'minus';
	};
	// }}}
	// {{{ refresh ()
	this.refresh = function ()
	{
		var l, s, folder, n;

		l = this._nodes;
		s = new String.buffer ();

		folder = document.getElementById ( 'folder:' + this.full_id ).lastChild;
		
		for ( n = 0; n < l; n ++ ) s.add ( this.list [ n ].render () );

		folder.innerHTML = s.toString ();
	};
	// }}}

	this._selected	   = 0; // Numero di nodi selezionati
	this._nodes	   = 0; // Numero di nodi figli

	// {{{ _add_node ( parent, child_status )
	this._add_node = function ( parent, child_status )
	{
		if ( ! parent ) return;

		var img = document.getElementById ( this._mk_img_id ( parent ) );

		if ( child_status == 2 ) parent._selected ++;
		if ( parent._selected >= parent._nodes )
		{
			parent._selected = parent._nodes;

			if ( parent.status != 2 )
			{
				parent.status = 2;
				this._add_node ( parent.parent, parent.status );
			}
		} else {
			parent.status = 1;
			this._add_node ( parent.parent, parent.status );
		}

		if ( img ) img.className = parent.tree.status_img [ parent.status ];
	};
	// }}}
	// {{{ _del_node ( parent, child_status )
	this._del_node = function ( parent, child_status )
	{
		if ( ! parent ) return;

		var img = document.getElementById ( this._mk_img_id ( parent ) );

		if ( child_status == 0 ) parent._selected --;
		if ( parent._selected <=  0 )
		{
			parent._selected = 0;
			if ( parent.status != 0 )
			{
				parent.status = 0;
				this._del_node ( parent.parent, parent.status );
			}
		} else {
			if ( parent.status != 1 ) this._del_node ( parent.parent, parent.status );
			parent.status = 1;
		}

		if ( img ) img.className = parent.tree.status_img [ parent.status ];
	};
	// }}}
	// {{{ _mk_img_id ( n )
	this._mk_img_id = function ( n )
	{
		return "img:" + n.tree.id + ":" + n.id;
	};
	// }}}
	// {{{ _mk_chkbox ( n, is_folder )
	this._mk_chkbox = function ( n, is_folder )
	{
		if ( ! n.tree.show_checkbox ) return '';
		if ( is_folder && ! n.tree.show_folder_checkbox ) return '<div class="space"></div>';

		var s = new String.buffer ();

		if ( ! is_folder ) s.add ( '<div class="space"></div>' );

		s.add ( '<div id="' + this._mk_img_id ( n ) + '"  class="' + n.tree.status_img [ n.status ] + '" ' );
		s.add ( ' onclick="OS3Tree.node_select(\'' + n.tree.id + '\', \'' + n.id + '\' )" ' );
		s.add ( '></div>' );


		return s.toString ();
	};
	// }}}
	// {{{ _mk_onclick ( n )
	this._mk_onclick = function ( n ) 
	{
		if ( ! n.onclick ) return n.text;

		return '<a href="javascript:' + n.onclick + '(\'' + n.tree.id + '\', \'' + n.id + '\')">' + n.text + '<\/a>';
	};
	// }}}
	// {{{ _mk_events ( n )
	this._mk_events = function ( n )
	{
		var s, id;
		// var padding = 11;
		var class_name;

		s = new String.buffer ();

		if ( n.is_selected )
			class_name = "sel";
		else
			class_name = "norm";

		s.add ('<div ' );

		id = this.tree.id + ":" + this.id;

		s.add ( ' id="' + id + '" ' );

		s.add ( " onmouseover=\"OS3Tree.evt(this,'hover')\"" );
		s.add ( " onmouseout=\"OS3Tree.evt(this,'out')\"" );
		s.add ( " onmousedown=\"OS3Tree.evt(this,'btn_down')\"" );
		s.add ( " onmouseup=\"OS3Tree.evt(this,'btn_up')\"" );
		s.add ( " onclick=\"OS3Tree.evt(this,'click')\"" );
		s.add ( " ondblclick=\"OS3Tree.evt(this,'dblclick')\"" );

		s.add ( ' class="' + class_name + '">' + this._mk_onclick ( this ) );

		s.add ( '</div>' );

		return s.toString ();
	};
	// }}}
};
// }}}
